package com.cater.shiro;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.apache.commons.codec.net.QCodec;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.permission.PermissionResolver;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import com.cater.common.BaseQuery;
import com.cater.common.UserContext;
import com.cater.query.CommonQuery;
import com.cater.sys.entity.Dep;
import com.cater.sys.entity.Resource;
import com.cater.sys.entity.Role;
import com.cater.sys.entity.User;
import com.cater.sys.service.DepService;
import com.cater.sys.service.ResourceService;
import com.cater.sys.service.RoleService;
import com.cater.sys.service.UserService;

/**
 * 自定义Realm,进行数据源配置
 * 
 * @author lanyuan 2014-12-25
 * @Email: mmm333zzz520@163.com
 * @version 3.0v
 */
public class MyRealm extends AuthorizingRealm {

	@Autowired
	private ResourceService resourcesService;

	@Autowired
	private UserService userService;

	@Autowired
	RoleService roleService;
	
	@Autowired
	DepService depService;
	
	SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");

	/**
	 * 只有需要验证权限时才会调用, 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.在配有缓存的情况下，只加载一次.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
		String loginName = SecurityUtils.getSubject().getPrincipal().toString();
		// 权限信息对象info,用来存放查出的用户的所有的角色（role）及权限（permission）
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		if (loginName != null) {
			Integer userId = (Integer) SecurityUtils.getSubject().getSession().getAttribute("user_in_session_id");
			List<Role> Role = roleService.getByuId(userId);
			List<Resource> rs= new ArrayList<Resource>();
			for (Role role2 : Role) {
				List<Resource> rss = resourcesService.getAllc(role2.getId());
				rs.addAll(rss);
				info.addRole(role2.getName());
			}
			
		
			// 用户的角色对应的所有权限，如果只使用角色定义访问权限
			for (Resource resources : rs) {
				if (StringUtils.isNotBlank(resources.getPermission())) {
					// 添加基于Permission的权限信息
					for (String permission : StringUtils.split(resources.getPermission(), ",")) {
						info.addStringPermission(permission);
					}
				}
			}
			return info;
		}
		return null;
	}

	@Override
	public void setPermissionResolver(PermissionResolver permissionResolver) {
		// TODO Auto-generated method stub
		super.setPermissionResolver(permissionResolver);
	}

	/**
	 * 认证回调函数,登录时调用
	 * 首先根据传入的用户名获取User信息；然后如果user为空，那么抛出没找到帐号异常UnknownManagerException；
	 * 如果user找到但锁定了抛出锁定异常LockedManagerException；最后生成AuthenticationInfo信息，
	 * 交给间接父类AuthenticatingRealm使用CredentialsMatcher进行判断密码是否匹配，
	 * 如果不匹配将抛出密码错误异常IncorrectCredentialsException；
	 * 另外如果密码重试此处太多将抛出超出重试次数异常ExcessiveAttemptsException；
	 * 在组装SimpleAuthenticationInfo信息时， 需要传入：身份信息（用户名）、凭据（密文密码）、盐（username+salt），
	 * CredentialsMatcher使用盐加密传入的明文密码和此处的密文密码进行匹配。
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws RuntimeException {
		String username = (String) token.getPrincipal();

		User user = userService.findByName(username);
		if (user != null) {
			if ("0".equals(user.getLocked())) {
				throw new LockedAccountException(); // 帐号锁定
			}
			// 从数据库查询出来的账号名和密码,与用户输入的账号和密码对比
			// 当用户执行登录时,在方法处理上要实现user.login(token);
			// 然后会自动进入这个类进行认证
			// 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配，如果觉得人家的不好可以自定义实现
			SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), // 用户名
					user.getPassword(), // 密码
					ByteSource.Util.bytes(""), // salt
					getName() // realm name
			);
			// 当验证都通过后，把用户信息放在session里
			UserContext.set(user);
			List<Role> role = roleService.getByuId(user.getId());
			UserContext.setRole(role);//存储用户角色
			UserContext.putId(user.getId());
			Dep dep = depService.getpidByuser(user.getId());
			if(dep.getCompanyId()==0){
				UserContext.setDepflog(true);
				UserContext.putdeppId(dep.getDepId());
			}else{
				UserContext.setDepflog(false);
				UserContext.putdeppId(dep.getCompanyId());
			}
			String userids = user.getId()+"";
			if(role!=null){
				Integer roletype = null;
				for (Role role2 : role) {
					if(roletype==null){
						roletype =role2.getRoleType() ;
					}
					if(roletype>role2.getRoleType()){
						roletype =role2.getRoleType() ;
					}
				}
				if(roletype==1){
					UserContext.setIsadmin(true);
				}else if (roletype==2) {
					//公司管理员
					CommonQuery query = new CommonQuery();
					query.setCompanyid(dep.getCompanyId());
					query.setDepId(null);
					List<User> companyusers = userService.getAllUserIds(query);
					for (User cuser : companyusers) {
						userids += ","+cuser.getId();
					}
				}else if (roletype==3) {
					//部门管理员
					CommonQuery query = new CommonQuery();
					query.setCompanyid(null);
					query.setDepId(user.getDepid());
					List<User> depusers = userService.getAllUserIds(query);
					for (User duser : depusers) {
						userids += ","+duser.getId();
					}
				}else{
					UserContext.setIsadmin(false);
				}
				UserContext.setIsadminType(roletype);//存储角色类型
				UserContext.setCompanyAllUserId(userids);
			}
			
			UserContext.setDataRole(user.getDatarole());
			UserContext.setDep(dep);
			user.setLastLoginIp(SecurityUtils.getSubject().getSession().getHost());
			user.setLastLoginTime(formatter.format(new Date()));
			userService.update(user);
			return authenticationInfo;
		} else {
			throw new UnknownAccountException();// 没找到帐号
		}
	}

	@Override
	protected void checkPermission(Permission permission, AuthorizationInfo info) {
		authorizationValidate(permission);
		super.checkPermission(permission, info);
	}

	@Override
	protected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) {
		if (permissions != null && !permissions.isEmpty()) {
			for (Permission permission : permissions) {
				authorizationValidate(permission);
			}
		}
		return super.isPermitted(permissions, info);
	}

	@Override
	public boolean isPermitted(PrincipalCollection principals, Permission permission) {
		authorizationValidate(permission);
		return super.isPermitted(principals, permission);
	}

	@Override
	protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {
		if (permissions != null && !permissions.isEmpty()) {
			for (Permission permission : permissions) {
				authorizationValidate(permission);
			}
		}
		return super.isPermittedAll(permissions, info);
	}

	/**
	 * 授权验证方法
	 * 
	 * @param permission
	 */
	private void authorizationValidate(Permission permission) {
		// 模块授权预留接口
	}

}